﻿using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using mEdit.Properties;

namespace mEdit.Controls
{
    /// <summary>
    /// 
    /// </summary>
    public partial class TreeTextEditor : UserControl
    {

        public TreeTextEditor()
        {
            InitializeComponent();
        }

        private bool _isContentChanged = false;
        public bool IsContentChanged
        {
            get { return _isContentChanged; }
        }

        bool _newFile = false;
        bool _nodeRemoved = false;

        public delegate void CurrentFileChangedDelegate(string fileName);
        public event CurrentFileChangedDelegate CurrentFileChanged;

        private void FireCurrentFileChanged(string filename)
        {
            if (CurrentFileChanged != null)
                CurrentFileChanged(filename);
        }

        public void OpenFile(string filename)
        {
            this._newFile = true;

            tree.Load(filename);
            Properties.Settings.Default.LastOpenedFile = filename;
            Properties.Settings.Default.LastDirectory = Path.GetDirectoryName(filename);
            FireCurrentFileChanged(filename);
        }

        public void SelectTreeView()
        {
            this.tree.Select();
        }

        public void SelectEditor()
        {
            this.editor.Focus();
        }

        private void tree_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Insert:
                    if (e.Modifiers == Keys.Control)
                        this.tree.AddChildNode();
                    else
                        this.tree.AddRootNode();
                    break;

                case Keys.Enter:
                    break;

                case Keys.E:
                    if (e.Modifiers == Keys.Control)
                        this.tree.RenameCurrentNode();
                    break;

                case Keys.Delete:
                    if (this.tree.Nodes.Count == 1) // take special action - rename node to 'rootNode', remove content
                    {
                        this.tree.ResetTheOnlyRootNode();
                        this.editor.Text = this.tree.Nodes[0].Tag as string;
                    }
                    else
                    {
                        _nodeRemoved = true;
                        this.tree.RemoveNode();
                        _nodeRemoved = false;
                    }
                    break;
            }
        }

        /// <summary>
        /// Save nodes, and restores cursor position
        /// </summary>
        private void SaveNodes()
        {
            // save nodes
            this.tree.Save();

            // restore position of the cursor in EditorTextBox
            this.editor.RestoreCursorPosition();
        }

        private void tree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if ((this.tree.SelectedNode != null) )
            {
                if (!_newFile && !_nodeRemoved)
                {
                    this.tree.SetLastSelectedNodeContent(editor.Text);
                }
                else
                {
                    _newFile = false;
                }
                this.tree.LastSelectedNode = this.tree.SelectedNode;
            }
            if (tree.SelectedNode != null)
                editor.Text = tree.SelectedNode.Tag as string;
        }

        // ==== ContextMenu 'Nodes'

        private void tsmiRenameNode_Click(object sender, EventArgs e)
        {
            this.tree.RenameCurrentNode();
        }

        private void tsmiAddNode_Click(object sender, EventArgs e)
        {
            this.tree.AddChildNode();
        }

        private void tsmiDeleteNode_Click(object sender, EventArgs e)
        {
            this.tree.RemoveNode();
        }

        private void tsmiAddRootNode_Click(object sender, EventArgs e)
        {
            this.tree.AddRootNode();
        }

        private void tsmiAddSibling_Click(object sender, EventArgs e)
        {
            this.tree.AddSiblingNode();
        }

        // ==== end of: ContexMenu 'Nodes'

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            tree_AfterSelect(null, null);
            this.SaveNodes();
        }

        private void ContentChanged()
        {
            if (!_isContentChanged)
            {
                this.SetChangeIndicator(true);
                _isContentChanged = true;
            }
        }

        private void editor_ContentChanged(object sender, EventArgs e)
        {
            ContentChanged();
        }

        private void editor_ContentSaveRequest(object sender, EventArgs e)
        {
            SaveContent();
        }

        private void ContentSaved()
        {
            if (this._isContentChanged)
            {
                this.SetChangeIndicator(false);
                _isContentChanged = false;
            }
        }

        private void tree_TreeContentChanged(object sender, EventArgs e)
        {
            ContentChanged();
        }

        private void tree_ContentSaveRequest(object sender, EventArgs e)
        {
            SaveContent();
        }

        private void SetChangeIndicator(bool change)
        {
            if ( change )
                this.Parent.Text += " *";
            else
                this.Parent.Text = this.Parent.Text.Remove(this.Parent.Text.Length - 2, 2);
        }

        public int LineNumberMarginWidth
        {
            get { return this.editor.LineNumberMarginWidth; }
        }

        public void Save(string fileName)
        {
            this.tree.Save(fileName);
        }

        public void ChangeEditorOutlook(Options options)
        {
            this.editor.BackColor = options.EditorBackColor;
            this.editor.ForeColor = options.EditorForeColor;
            this.editor.LinesForeColor = options.LineForeColor;
            this.editor.LinesBackColor = options.LineBackColor;
            this.editor.EditorFont = options.EditorFont;

            this.editor.SetEncodingsAndCharset(options.EncodingName, options.EditorFont.GdiCharSet, options.EditorFont);
        }

        private void LoadEditorOptions()
        {
            this.editor.EditorForeColor = Properties.Settings.Default.EditorForeColor;
            this.editor.EditorBackColor = Properties.Settings.Default.EditorBackColor;
            this.editor.LinesBackColor = Properties.Settings.Default.LineBackColor;
            this.editor.LinesForeColor = Properties.Settings.Default.LineForeColor;

            Font tempFont = Properties.Settings.Default.EditorFont;
            Font properFont = new Font(tempFont.FontFamily, tempFont.Size, tempFont.Style, tempFont.Unit, Properties.Settings.Default.GDICharSet);
            this.editor.EditorFont = properFont;

            this.editor.SetEncodingsAndCharset(Settings.Default.Encoding, Settings.Default.GDICharSet, Settings.Default.EditorFont);

            this.editor.LineNumberMarginWidth = Settings.Default.MarginWidth;
            if (Settings.Default.SplitterDistance != -1)
                this.splitContainer.SplitterDistance = Settings.Default.SplitterDistance;
        }

        public void SaveContent()
        {
            this.tree.SetLastSelectedNodeContent(this.editor.Text);
            this.SaveNodes();
            this.editor.NotifyContentSaved();
            this.tree.NotifyContentSaved();

            ContentSaved();
        }

        public void CreateNew()
        {
            tree.CreateNew();
            editor.CreateNew();
            _isContentChanged = false;
            FireCurrentFileChanged(string.Empty);
        }

        private void splitContainer_SplitterMoved(object sender, SplitterEventArgs e)
        {
            Settings.Default.SplitterDistance = this.splitContainer.SplitterDistance;
            Settings.Default.Save();
        }

        private void TreeTextEditor_Load(object sender, EventArgs e)
        {
            this.LoadEditorOptions();
            this.splitContainer.SplitterMoved +=new SplitterEventHandler(splitContainer_SplitterMoved);
        }

        private void tree_SwapFocus(object sender, EventArgs e)
        {
            this.SelectEditor();
        }

        private void editor_SwapFocus(object sender, EventArgs e)
        {
            this.SelectTreeView();
        }
    }
}